package com.wei.czz.framework.common.helper;

import com.wei.czz.common.constant.Constant;
import com.wei.czz.common.constant.EntityConstant;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.dto.common.NameValue;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.common.multiDIct.MultiDictEnum;
import com.wei.czz.common.utils.RandomNumUtils;
import com.wei.czz.framework.common.entity.MultiDictEntity;
import com.wei.czz.framework.common.handler.redis.RedisStringHandler;
import com.wei.czz.framework.common.service.MultiDictService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2025-02-21 15:27:53
 * className: MultiDictHelper 级联字典帮助类
 * version: 1.0
 * description:
 */
@Component
@AllArgsConstructor
public class MultiDictHelper {

    private static final Logger log = LoggerFactory.getLogger(MultiDictHelper.class);

    private final MultiDictService multiDictService;

    private final RedisStringHandler redisStringHandler;

    private final RedissonClient redissonClient;

    /**
     * 获取级联字典列表操作
     * @param multiDictEnum 级联字典枚举
     * @return 级联字典列表
     */
    public List<MultiDictEntity> getList(MultiDictEnum multiDictEnum) {

        /*
            从缓存中获取级联字典列表
         */
        String redisKey = RedisConstant.STRING + EntityConstant.MULTI_DICT + Constant.UNDER + RedisConstant.LIST
                + multiDictEnum.getValue();
        List<MultiDictEntity> multiDictList = redisStringHandler.get(redisKey);
        if (!CollectionUtils.isEmpty(multiDictList)) {
            log.info("从缓存中获取到级联字典列表");
            return multiDictList;
        }

        String lockKey = RedisConstant.LOCK + redisKey + RedisConstant.SPLIT + RandomNumUtils.getRandomNum(3);
        RLock lock = redissonClient.getLock(lockKey);
        // 尝试加锁
        boolean bool = lock.tryLock();
        log.info("获取级联字典列表，尝试加锁完成。lockKey={} bool={}", lockKey, bool);
        if (!bool) {
            // 加锁
            lock.lock();
            log.info("获取级联字典列表，加锁成功");
        }

        try {
            if (!bool) {
                // double check
                multiDictList = redisStringHandler.get(redisKey);
                if (!CollectionUtils.isEmpty(multiDictList)) {
                    log.info("double check—>从缓存中获取到级联字典列表");
                    return multiDictList;
                }
            }

            /*
                从数据库中获取级联字典列表
             */
            multiDictList = multiDictService.findList(multiDictEnum);

            /*
                缓存级联字典列表（30分钟）
             */
            redisStringHandler.set(redisKey, multiDictList, 30, TimeUnit.MINUTES);

            return multiDictList;

        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                // 解锁
                lock.unlock();
            }
        }

    }

    /**
     * 获取级联字典名称-值列表
     * @param multiDictEnum 级联字典枚举
     * @return 名称-值列表
     */
    public List<NameValue<String>> getNameValueList(MultiDictEnum multiDictEnum) {

        /*
            获取级联字典列表
         */
        List<MultiDictEntity> multiDictList = this.getList(multiDictEnum);
        if (CollectionUtils.isEmpty(multiDictList)) {
            log.info("获取级联字典名称-值列表，枚举列表为空。multiDictName={}", multiDictEnum.getName());
            return Collections.emptyList();
        }

        // 列表映射
        return multiDictList.stream()
                .filter(multiDict -> Objects.equals(multiDict.getStatus(), CommonEnum.ZERO.getValue()))
                .map(multiDict -> {
                   NameValue<String> nameValue = new NameValue<>();
                   nameValue.setName(multiDict.getName());
                   nameValue.setValue(multiDict.getValue());

                   return nameValue;
                })
                .collect(Collectors.toList());
    }

    /**
     * 获取级联字典名称-映射值列表
     * @param multiDictEnum 级联字典枚举
     * @param function      映射函数
     * @param <T>           泛型
     * @return 名称-值列表
     */
    public <T> List<NameValue<T>> getNameValueList(MultiDictEnum multiDictEnum, Function<MultiDictEntity, T> function) {

        /*
            获取级联字典列表
         */
        List<MultiDictEntity> multiDictList = this.getList(multiDictEnum);
        if (CollectionUtils.isEmpty(multiDictList)) {
            log.info("获取级联字典名称-映射值列表，枚举列表为空。multiDictName={}", multiDictEnum.getName());
            return Collections.emptyList();
        }

        // 列表映射
        return multiDictList.stream()
                .filter(multiDict -> Objects.equals(multiDict.getStatus(), CommonEnum.ZERO.getValue()))
                .map(multiDict -> {
                    NameValue<T> nameValue = new NameValue<>();
                    nameValue.setName(multiDict.getName());
                    nameValue.setValue(function.apply(multiDict));

                    return nameValue;
                })
                .collect(Collectors.toList());
    }

    /**
     * 获取值对应的名称
     * @param multiDictEnum 级联字典枚举
     * @param value         值
     * @return 名称
     */
    public String findName(MultiDictEnum multiDictEnum, String value) {
        /*
            获取级联字典列表
         */
        List<MultiDictEntity> multiDictList = this.getList(multiDictEnum);
        if (CollectionUtils.isEmpty(multiDictList)) {
            log.info("获取值对应的名称，枚举列表为空。multiDictName={}", multiDictEnum.getName());
            return StringUtils.EMPTY;
        }

        String name = multiDictList.stream()
                .filter(multiDict -> Objects.equals(multiDict.getValue(), value))
                .findFirst()
                .map(MultiDictEntity::getName)
                .orElse(StringUtils.EMPTY);
        log.info("级联字典名称。value={} name={}", value, name);
        return name;
    }

    /**
     * 获取值对应的名称
     * @param multiDictEnum 级联字典枚举
     * @param value         值
     * @return 名称
     */
    public String findName(MultiDictEnum multiDictEnum, Integer value) {
        if (Objects.isNull(value)) {
            log.info("获取值对应的名称，值为空。multiDictName={}", multiDictEnum.getName());
            return StringUtils.EMPTY;
        }
        return this.findName(multiDictEnum, value.toString());
    }

    /**
     * 获取值对应的名称
     * @param multiDictEnum 级联字典枚举
     * @param value         值
     * @param biPredicate   断言
     * @param <T>           泛型
     * @return 名称
     */
    public <T> String findName(MultiDictEnum multiDictEnum, T value, BiPredicate<MultiDictEntity, T> biPredicate) {
        if (Objects.isNull(value)) {
            log.info("获取值对应的名称，泛型值为空。multiDictName={}", multiDictEnum.getName());
            return StringUtils.EMPTY;
        }
        /*
            获取级联字典列表
         */
        List<MultiDictEntity> multiDictList = this.getList(multiDictEnum);
        if (CollectionUtils.isEmpty(multiDictList)) {
            log.info("获取泛型值对应的名称，枚举列表为空。multiDictName={}", multiDictEnum.getName());
            return StringUtils.EMPTY;
        }
        String name = multiDictList.stream()
                .filter(multiDict -> biPredicate.test(multiDict, value))
                .findFirst()
                .map(MultiDictEntity::getName)
                .orElse(StringUtils.EMPTY);
        log.info("泛型值对应的名称。value={} name={}", value, name);
        return name;
    }



}
